package cmd

import (
	"file-cleaner/internal/logger"
	"file-cleaner/internal/pkg/file_cleaner"
	"file-cleaner/internal/pkg/file_cleaner/clean_handler"
	"file-cleaner/internal/pkg/file_cleaner/query_handler"
	"time"
)

type fileCleaner struct {
	api file_cleaner.FileCleanerApi
}

func (f fileCleaner) run() {
	if f.api == nil {
		logger.Fatal("nil FileCleanerApi")
		return
	}

	err := f.api.Run()
	if err != nil {
		logger.Fatal(err)
	}

	err = f.api.Query(path, true)
	if err != nil {
		logger.Fatal(err)
	}

	f.api.Done()
}

func newFileCleaner(queryHandlers []query_handler.QueryHandler, beforeCleanHandlers, mainCleanHandlers, troubleshootingCleanHandlers, finishCleanHandlers []clean_handler.CleanHandler) fileCleaner {
	api, err := file_cleaner.NewFileCleanerApi(goroutine, queryHandlers, beforeCleanHandlers, mainCleanHandlers, troubleshootingCleanHandlers, finishCleanHandlers)
	if err != nil {
		logger.Fatal(err)
	}
	return fileCleaner{api: api}
}

func genDryRunCleaner() fileCleaner {
	queryHandlers := make([]query_handler.QueryHandler, 0)
	mainHandlers := make([]clean_handler.CleanHandler, 0)

	genTimeQueryHandler(&queryHandlers)
	genHashQueryHandler(&queryHandlers)

	genDryRunCleanHandler(&mainHandlers)

	return newFileCleaner(queryHandlers, nil, mainHandlers, nil, nil)
}

func genDeleteFileCleaner() fileCleaner {
	queryHandlers := make([]query_handler.QueryHandler, 0)
	beforeCleanHandlers := make([]clean_handler.CleanHandler, 0)
	mainCleanHandlers := make([]clean_handler.CleanHandler, 0)
	troubleshootingCleanHandlers := make([]clean_handler.CleanHandler, 0)
	finishCleanHandlers := make([]clean_handler.CleanHandler, 0)

	genTimeQueryHandler(&queryHandlers)
	genQueryHandlerForDeleteOnly(&queryHandlers)

	genBackupFileCleanHandler(&beforeCleanHandlers)

	genDeleteFileCleanHandler(&mainCleanHandlers)

	genRollbackCleanHandler(&troubleshootingCleanHandlers)

	genReleaseBackupCleanHandler(&finishCleanHandlers)

	return newFileCleaner(queryHandlers, beforeCleanHandlers, mainCleanHandlers, troubleshootingCleanHandlers, finishCleanHandlers)
}

func genLinkFileCleaner() fileCleaner {
	queryHandlers := make([]query_handler.QueryHandler, 0)
	beforeCleanHandlers := make([]clean_handler.CleanHandler, 0)
	mainCleanHandlers := make([]clean_handler.CleanHandler, 0)
	troubleshootingCleanHandlers := make([]clean_handler.CleanHandler, 0)
	finishCleanHandlers := make([]clean_handler.CleanHandler, 0)

	genTimeQueryHandler(&queryHandlers)
	genHashQueryHandler(&queryHandlers)

	genBackupFileCleanHandler(&beforeCleanHandlers)

	genDeleteFileCleanHandler(&mainCleanHandlers)
	genLinkFileCleanHandler(&mainCleanHandlers)

	genRollbackCleanHandler(&troubleshootingCleanHandlers)

	genReleaseBackupCleanHandler(&finishCleanHandlers)

	return newFileCleaner(queryHandlers, beforeCleanHandlers, mainCleanHandlers, troubleshootingCleanHandlers, finishCleanHandlers)
}

// generate query handler funcs
func genTimeQueryHandler(handlers *[]query_handler.QueryHandler) {
	var (
		layoutStr = "2006-01-02 15:04:05"
	)
	if timeAfter == "" {
		timeAfter = "1970-01-01 00:00:00"
	}

	if timeBefore == "" {
		timeBefore = time.Now().Format(layoutStr)
	}

	ta, err := time.Parse(layoutStr, timeAfter)
	if err != nil {
		panic(err)
	}
	tb, err := time.Parse(layoutStr, timeBefore)
	if err != nil {
		panic(err)
	}

	var timeQuery query_handler.QueryHandler
	switch timeType {
	case "atime":
		timeQuery = query_handler.QueryByATimeImpl{
			AfterTime:  ta,
			BeforeTime: tb,
		}
	case "ctime":
		timeQuery = query_handler.QueryByCTimeImpl{
			AfterTime:  ta,
			BeforeTime: tb,
		}
	case "mtime":
		timeQuery = query_handler.QueryByMTimeImpl{
			AfterTime:  ta,
			BeforeTime: tb,
		}
	default:
		return
	}

	*handlers = append(*handlers, timeQuery)
}

func genHashQueryHandler(handlers *[]query_handler.QueryHandler) {
	*handlers = append(*handlers, new(query_handler.QueryHashImpl))
}

func genQueryHandlerForDeleteOnly(handlers *[]query_handler.QueryHandler) {
	*handlers = append(*handlers, new(query_handler.QueryForDeleteOnlyImpl))
}

// generate before clean handler funcs
func genBackupFileCleanHandler(handlers *[]clean_handler.CleanHandler) {
	*handlers = append(*handlers, new(clean_handler.BackupHandlerImpl))
}

// generate main clean handler funcs
func genDryRunCleanHandler(handlers *[]clean_handler.CleanHandler) {
	*handlers = append(*handlers, new(clean_handler.DryRunImpl))
}

func genDeleteFileCleanHandler(handlers *[]clean_handler.CleanHandler) {
	*handlers = append(*handlers, new(clean_handler.DeleteFileImpl))
}

func genLinkFileCleanHandler(handlers *[]clean_handler.CleanHandler) {
	//genDeleteFileCleanHandler(handlers)
	*handlers = append(*handlers, new(clean_handler.LinkFileImpl))
}

// generate troubleshooting clean handler funcs
func genRollbackCleanHandler(handlers *[]clean_handler.CleanHandler) {
	*handlers = append(*handlers, new(clean_handler.RollbackHandlerImpl))
}

// generate finish clean handler funcs
func genReleaseBackupCleanHandler(handlers *[]clean_handler.CleanHandler) {
	*handlers = append(*handlers, new(clean_handler.ReleaseBackupHandlerImpl))
}
